'<<<<<<<<<<<<<<<<<<<<<<<< Plugin Interface : >>>>>>>>>>
'>>>>>>>>>>>>>>>>>>>>>>>> Iplugin <<<<<<<<<<<<<<<<<<<<<
'>>>>>>>>>>>this script goes in its own class project called plugin interface<<<<<<<<<<<
'>>>>>>>>>>>the class is to be added to the main project and reffernced by the plugin created<<<<<<<<<<<<<

''' <summary>
''' This interface allows for the main script to execute plugins, the plugins must implement this interface
''' by building an interface the main script know which functions are available in the plugin
'''
''' </summary>
''' <remarks></remarks>
Public Interface IPlugin
    ''' <summary>
    ''' This is the name of the Plugin Name = "MyPlugin"
    ''' </summary>
    ''' <value></value>
    ''' <returns>this is s tring of the name of the plugin this is an identifier for the main script</returns>
    ''' <remarks></remarks>
    ReadOnly Property Name As String
    ''' <summary>
    ''' this is the response to be returned to the main script
    ''' </summary>
    ''' <value></value>
    ''' <returns>String: the response that is generated by the plugin
    ''' is stored here for retreival by the main script</returns>
    ''' <remarks></remarks>
    Property Response As String
    ''' <summary>
    ''' This is the response algorythm, this is the main function
    ''' the user input is sent to this function
    ''' </summary>
    ''' <param name="UserInput"></param>
    ''' <returns>True : If a response has been found</returns>
    ''' <remarks></remarks>
    Function GetResponse(ByVal UserInput As String) As Boolean
End Interface

'<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Plugin Host.VB>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'
'<<<<<<<<<<<<this script goes inside the main form or in its own file in the main project solution>>>>>>>>>>>>>'
Imports PluginInterface
Public Class PluginHost
    Private _Plugins As Dictionary(Of String, IPlugin)
    Private UserInput As String = ""
    Private Mresponse As String
    ''' <summary>
    ''' response held in the class
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Response As String
        Get
            Return Mresponse
        End Get
    End Property
    ''' <summary>
    ''' Executes plugins in folder \plugins, adds subsequent responses to response
    ''' </summary>
    ''' <param name="_UserInput"></param>
    ''' <remarks></remarks>
    Private Sub ExecutePlugin(ByVal _UserInput As String)
        _Plugins = New Dictionary(Of String, IPlugin)
        Dim plugins As ICollection(Of IPlugin) = PluginLoader.LoadPlugins(Application.StartupPath & "\Plugins")
        If plugins Is Nothing Then

            Return
        End If
        For Each item In plugins
            If item.GetResponse(_UserInput) = True Then
                SetResponse(item.Response)
            End If
        Next
    End Sub
    ''' <summary>
    ''' hee responses are chained together
    ''' </summary>
    ''' <param name="Response"></param>
    ''' <remarks></remarks>
    Private Sub SetResponse(ByVal Response As String)
        Mresponse = LTrim(Mresponse) & " " & Response
    End Sub
    ''' <summary>
    ''' executes all plugins returning the chained response
    ''' </summary>
    ''' <param name="_UserInput"></param>
    ''' <returns>response string</returns>
    ''' <remarks></remarks>
    Public Function Execute(ByVal _UserInput As String) As String
        ExecutePlugin(_UserInput)
        Return Mresponse
    End Function
End Class

'<<<<<<<<<<<<<<<<<<<<<<<<<<<<this module, function is called by the main script to load plugins found >>>>>>>>>>>>>>>'
'<<<<<<<<<<<<<<<<<<<<<<<<<<<<<this is to be added to the main project >>>>>>>>>>>>>>>>>>>>>>'

Imports PluginInterface
Imports System.IO
Imports System.Reflection
Module PluginLoader
    ''' <summary>
    ''' searches the given path for assemblies of type dll, and Iplugin(interface to be used for all plugins)
    ''' </summary>
    ''' <param name="path"></param>
    ''' <returns>Collection of plugin objects</returns>
    ''' <remarks></remarks>
    Public Function LoadPlugins(path As String) As ICollection(Of IPlugin)
        Dim dllFileNames As String()
        If Directory.Exists(path) Then
            dllFileNames = Directory.GetFiles(path, "*.dll")

            Dim assemblies As ICollection(Of Assembly) = New List(Of Assembly)(dllFileNames.Length)
            For Each dllFile As String In dllFileNames
                Dim an As AssemblyName = AssemblyName.GetAssemblyName(dllFile)
                Dim assembly As Assembly = assembly.Load(an)
                assemblies.Add(assembly)
            Next
            Dim pluginType As Type = GetType(IPlugin)
            Dim pluginTypes As ICollection(Of Type) = New List(Of Type)
            For Each assembly As Assembly In assemblies
                If assembly <> Nothing Then
                    Dim types As Type() = assembly.GetTypes()
                    For Each type As Type In types
                        If type.IsInterface Or type.IsAbstract Then
                            Continue For
                        Else
                            If type.GetInterface(pluginType.FullName) <> Nothing Then
                                pluginTypes.Add(type)
                            End If
                        End If
                    Next
                End If
            Next
            Dim plugins As ICollection(Of IPlugin) = New List(Of IPlugin)(pluginTypes.Count)
            For Each type As Type In pluginTypes
                Dim plugin As IPlugin = Activator.CreateInstance(type)
                plugins.Add(plugin)
            Next
            Return plugins
        End If
        Return Nothing
    End Function
End Module


